package tool;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;

import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

@SuppressWarnings("serial")
public class AutoresizeTextArea extends JTextArea implements DocumentListener,
		ComponentListener
{

	private Font font = new Font("Arial", 0, 10);

	public AutoresizeTextArea()
	{
		super();
		init();
	}

	public AutoresizeTextArea(String s)
	{
		super(s);
		init();
	}

	private void init()
	{
		this.setLineWrap(true);
		this.setWrapStyleWord(true);
		this.getDocument().addDocumentListener(this);
		this.addComponentListener(this);
		this.setFocusable(false);
	}

	public void adjustFont()
	{
		if (isVisible())
		{
			Dimension size = this.getSize();
			Font newFont = calculateFont(this.font, this.getText(), size);
			this.setFont(newFont);
		}
	}

	private Font calculateFont(Font baseFont, String text, Dimension maxSize)
	{
		int linebreaks = text.split("\n").length;

		Dimension textSize = getSize(baseFont, text);
		float goodSize;
		if (compare(maxSize, textSize, linebreaks) > 0.0)
		{
			// font is small enough
			// can we make it bigger?
			float checkSize = baseFont.getSize2D();
			do
			{
				goodSize = checkSize;
				checkSize++;
				Font checkFont = baseFont.deriveFont(checkSize);
				textSize = getSize(checkFont, text);
			} while (compare(maxSize, textSize, linebreaks) > 0.0);
		}
		else
		{
			// font is to big
			// try to make it smaller
			float checkSize = baseFont.getSize2D();
			do
			{
				checkSize--;
				Font checkFont = baseFont.deriveFont(checkSize);
				textSize = getSize(checkFont, text);
			} while (compare(maxSize, textSize, linebreaks) < 0.0);
			goodSize = checkSize;
		}
		Font result = baseFont.deriveFont(goodSize);
		return result;
	}

	private Dimension getSize(Font font, String text)
	{
		FontMetrics metrics = this.getFontMetrics(font);
		Rectangle bounds = metrics.getStringBounds(text, this.getGraphics())
				.getBounds();
		return bounds.getSize();
	}

	private double compare(Dimension compSize, Dimension textSize,
			int textLineBreaks)
	{
		double numOfLines = textSize.getWidth() / compSize.getWidth();
		numOfLines = Math.ceil(numOfLines) + textLineBreaks;
		double newTextWidth = compSize.getWidth();
		double newTextHeight = numOfLines * textSize.getHeight();
		double aComp = compSize.getHeight() * compSize.getWidth();
		double aText = newTextHeight * newTextWidth;
		return aComp - aText;
	}

	@Override
	public void changedUpdate(DocumentEvent arg0)
	{
	}

	@Override
	public void insertUpdate(DocumentEvent arg0)
	{
		adjustFont();
	}

	@Override
	public void removeUpdate(DocumentEvent arg0)
	{
	}

	@Override
	public void componentHidden(ComponentEvent arg0)
	{
	}

	@Override
	public void componentMoved(ComponentEvent arg0)
	{
	}

	@Override
	public void componentResized(ComponentEvent arg0)
	{
		adjustFont();
	}

	@Override
	public void componentShown(ComponentEvent arg0)
	{
	}
}
